package com.bestv.search.engine.servlet;

import com.bestv.search.common.util.StringConst;
import com.bestv.search.engine.command.InfoCommand;
import com.bestv.search.engine.command.TopNCommand;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.dom4j.Document;
import org.dom4j.Node;
import org.dom4j.io.SAXReader;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLDecoder;

/**
 * @author Michael Wang
 */

// $Id: TopNServlet.java 23 2012-03-12 06:30:55Z wbwang $
public class TopNServlet extends HttpServlet {

    private static final long serialVersionUID = -5949041496911483044L;
    private static final int DEFAULT_TOPN_LIMIT = 10;
    protected final Log log = LogFactory.getLog(getClass());
    private TopNCommand topNCommand;
    private InfoCommand infoCommand;

    public TopNServlet() {
        super();
    }

    public void init() throws ServletException {
        super.init();
        ServletContext application = getServletContext();
        WebApplicationContext wac = WebApplicationContextUtils.getWebApplicationContext(application);
        topNCommand = (TopNCommand) wac.getBean("topn");
        infoCommand = (InfoCommand) wac.getBean("infoCommand");
    }

    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setContentType("text/html;charset=UTF-8");
        String hStr = URLDecoder.decode(req.getParameter("q"), "UTF-8");
        doExcute(hStr, resp);
    }

    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String hStr = URLDecoder.decode(req.getParameter("q"), "UTF-8");
        doExcute(hStr, resp);
    }

    private void doExcute(String sReq, HttpServletResponse response) throws IOException {
        sReq = new String(sReq.getBytes("iso-8859-1"), "utf-8");
        log.debug("topNStr: " + sReq);
        SAXReader reader = new SAXReader();
        Document doc = null;
        InputStream xmlInputStream = new ByteArrayInputStream(sReq.getBytes("UTF-8"));
        try {
            doc = reader.read(xmlInputStream);
        } catch (Exception e) {
            response.getWriter().write("Error!The Request Parameter cannot parse to XML");
            return;
        } finally {
            xmlInputStream.close();
        }
        String cmd = doc.selectSingleNode("/request/cmd").getText();
        if (cmd.equalsIgnoreCase("topn") || cmd.equalsIgnoreCase("topnInfo")) {
            // Gets limit
            Node limitNode = doc.selectSingleNode("/request/limit");
            int limit = DEFAULT_TOPN_LIMIT;
            if (limitNode != null && !"".equals(limitNode.getText().trim())) {
                try {
                    limit = Integer.valueOf(limitNode.getText().trim());
                } catch (Exception e) {
                    log.warn("Parse limit node to integer error!");
                    limit = DEFAULT_TOPN_LIMIT;
                }
            }

            // Gets type, default is Merge
            Node typeNode = doc.selectSingleNode("/request/type");
            String type = "Merge";
            if (typeNode != null && !"".equals(typeNode.getText().trim())) {
                type = typeNode.getText().trim();
            }

            // If type == week, changed to 'weekly', due to the original
            // value is week, but the new value should be weekly
            if (type.equalsIgnoreCase(StringConst.WEEK)) {
                type = StringConst.WEEKLY;
            }

            // If type == month, changed to 'monthly', due to the original
            // value is month, but the new value should be monthly
            if (type.equalsIgnoreCase(StringConst.MONTH)) {
                type = StringConst.MONTHLY;
            }

            // Gets increase flag
            Node increaseNode = doc.selectSingleNode("/request/increase");
            boolean increase = true;
            if (increaseNode != null && !"".equals(increaseNode.getText().trim())) {
                try {
                    increase = Boolean.parseBoolean(increaseNode.getText().trim());
                } catch (Exception e) {
                    log.warn("Parse increase node to boolean error!");
                    increase = true;
                }
            }

            // Gets limit
            Node mergeTypeNode = doc.selectSingleNode("/request/mergeType");
            int mergeType = 1;
            if (mergeTypeNode != null && !"".equals(mergeTypeNode.getText().trim())) {
                try {
                    mergeType = Integer.valueOf(mergeTypeNode.getText().trim());
                } catch (Exception e) {
                    log.warn("Parse limit node to integer error!");
                    mergeType = DEFAULT_TOPN_LIMIT;
                }
            }

            // Gets limit
            Node categoryTypeNode = doc.selectSingleNode("/request/category");
            String[] categorys = null;
            if (categoryTypeNode != null && !"".equals(categoryTypeNode.getText().trim())) {
                try {
                    categorys = categoryTypeNode.getText().trim().split(" ");
                } catch (Exception e) {
                    log.warn("Parse limit node to integer error!");
                    categorys = null;
                }
            }

            String rsp = null;
            if (cmd.equalsIgnoreCase("topn")) {
                rsp = topNCommand.topn(type, increase, mergeType, limit);
            } else {
                rsp = infoCommand.topn(type, increase, mergeType, limit, categorys);
            }
            log.debug(">>>> rsp:\n" + rsp);
            response.getWriter().write(rsp);
        } else {
            log.error("It doesn't match the topn command.");
            log.error(doc.asXML());
            return;
        }
    }
}
